﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.IO;
using System.Windows.Media.Imaging;

namespace ThuPhap
{
    public partial class ChooseImage : PhoneApplicationPage
    {
        public static Stream PhotoStream;
        private double TotalImageScale = 1d;
        private Point ImagePosition = new Point(0, 0);
        private BitmapSource bitmapSource;
        private const double OPACITY = 0;

        private double MAX_IMAGE_ZOOM = 5;
        private Point _oldFinger1;
        private Point _oldFinger2;
        private double _oldScaleFactor;
        private string IsCamera = string.Empty;

        public delegate void FinishChooseImageDelegate(BitmapSource Image);
        public static event FinishChooseImageDelegate FinishChooseImageEvent;

        public ChooseImage()
        {
            InitializeComponent();
            
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            
            if (NavigationContext.QueryString.TryGetValue("camera", out IsCamera))
            {
                
            }
            BitmapImage bitmap = new BitmapImage();
            bitmap.SetSource(PhotoStream);
            if (IsCamera == "t")
            {
                WriteableBitmap writeableBitmap = new WriteableBitmap(bitmap);
                if (bitmap.PixelWidth > bitmap.PixelHeight)
                    writeableBitmap = writeableBitmap.Rotate(90);
                else
                    writeableBitmap = writeableBitmap.Rotate(-90);
                bitmapSource = bitmap;
                ImgZoom.Source = writeableBitmap;
                
            }
            else
            {
                bitmapSource = bitmap;
                ImgZoom.Source = bitmap;
            }
            
            ImgZoom.UpdateLayout();
            SetPicture();
        }

        System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle();
        private void SetPicture()
        {
            var r = (from c in this.ImageView.Children where c.Opacity == OPACITY select c);
            if (r.Count() == 0)
            {
                try
                {
                    rect.Opacity = OPACITY;
                    //rect.Fill = new SolidColorBrush(Colors.White);
                    //Tỷ lệ 5:3
                    var point = this.ConvertRatio(ImgZoom.ActualWidth, ImgZoom.ActualHeight);
                    rect.Height = point.Y;
                    rect.MaxHeight = point.Y;
                    rect.MaxWidth = point.X;
                    rect.Width = point.X;
                    rect.Stroke = new SolidColorBrush(Colors.White);
                    rect.StrokeThickness = 2;
                    ViewAreaRectangle.Width = point.X;
                    ViewAreaRectangle.Height = point.Y;
                    this.ImageView.Children.Add(rect);
                }
                catch { }
            }
        }

        private Point ConvertRatio(double Width, double Height)
        {
            //Check ratio 5:3
            double pointer = 1.0f;
            double constRation = (5 * pointer / 3 * pointer);
            double realRation = (Height * pointer) / (Width * pointer);
            if (realRation == constRation)
            {
                return new Point(Width, Height);
            }
            else if (realRation < constRation)
            {
                return new Point(3 * (Height * pointer / 5), Height);
            }
            else
            {
                return new Point(Width, 5 * (Width * pointer / 3));
            }
        }




        #region Event handlers

        /// <summary>
        /// Initializes the zooming operation
        /// </summary>
        private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
        {
            _oldFinger1 = e.GetPosition(ImgZoom, 0);
            _oldFinger2 = e.GetPosition(ImgZoom, 1);
            _oldScaleFactor = 1;
        }

        /// <summary>
        /// Computes the scaling and translation to correctly zoom around your fingers.
        /// </summary>
        private void OnPinchDelta(object sender, PinchGestureEventArgs e)
        {

            var scaleFactor = e.DistanceRatio / _oldScaleFactor;
            if (!IsScaleValid(scaleFactor))
                return;

            var currentFinger1 = e.GetPosition(ImgZoom, 0);
            var currentFinger2 = e.GetPosition(ImgZoom, 1);

            var translationDelta = GetTranslationDelta(
                currentFinger1,
                currentFinger2,
                _oldFinger1,
                _oldFinger2,
                ImagePosition,
                scaleFactor);

            _oldFinger1 = currentFinger1;
            _oldFinger2 = currentFinger2;
            _oldScaleFactor = e.DistanceRatio;

            UpdateImageScale(scaleFactor);
            UpdateImagePosition(translationDelta);
        }

        /// <summary>
        /// Moves the image around following your finger.
        /// </summary>
        private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
        {
            var translationDelta = new Point(e.HorizontalChange, e.VerticalChange);

            if (IsDragValid(1, translationDelta))
            {
                UpdateImagePosition(translationDelta);
                //System.Windows.Shapes.Rectangle rec = (System.Windows.Shapes.Rectangle)(from c in this.ImageView.Children where c.Opacity == OPACITY select c).First();
                //GeneralTransform gt = rec.TransformToVisual(ImgZoom);
                //var point = gt.Transform(new Point(0, 0));
            }

        }

        /// <summary>
        /// Resets the image scaling and position
        /// </summary>
        private void OnDoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
        {
            ResetImagePosition();
        }

        #endregion

        #region Utils

        /// <summary>
        /// Computes the translation needed to keep the image centered between your fingers.
        /// </summary>
        private Point GetTranslationDelta(
            Point currentFinger1, Point currentFinger2,
            Point oldFinger1, Point oldFinger2,
            Point currentPosition, double scaleFactor)
        {
            var newPos1 = new Point(
             currentFinger1.X + (currentPosition.X - oldFinger1.X) * scaleFactor,
             currentFinger1.Y + (currentPosition.Y - oldFinger1.Y) * scaleFactor);

            var newPos2 = new Point(
             currentFinger2.X + (currentPosition.X - oldFinger2.X) * scaleFactor,
             currentFinger2.Y + (currentPosition.Y - oldFinger2.Y) * scaleFactor);

            var newPos = new Point(
                (newPos1.X + newPos2.X) / 2,
                (newPos1.Y + newPos2.Y) / 2);

            return new Point(
                newPos.X - currentPosition.X,
                newPos.Y - currentPosition.Y);
        }

        /// <summary>
        /// Updates the scaling factor by multiplying the delta.
        /// </summary>
        private void UpdateImageScale(double scaleFactor)
        {
            TotalImageScale *= scaleFactor;
            ApplyScale();
        }

        /// <summary>
        /// Applies the computed scale to the image control.
        /// </summary>
        private void ApplyScale()
        {
            ((CompositeTransform)ImgZoom.RenderTransform).ScaleX = TotalImageScale;
            ((CompositeTransform)ImgZoom.RenderTransform).ScaleY = TotalImageScale;
        }

        /// <summary>
        /// Updates the image position by applying the delta.
        /// Checks that the image does not leave empty space around its edges.
        /// </summary>
        private void UpdateImagePosition(Point delta)
        {

            var newPosition = new Point(ImagePosition.X + delta.X, ImagePosition.Y + delta.Y);

            if (newPosition.X > (ImgZoom.ActualWidth - rect.Width) / 2)
                newPosition.X = (ImgZoom.ActualWidth - rect.Width) / 2;
            if (newPosition.Y > 0)
                newPosition.Y = 0;

            if ((ImgZoom.ActualWidth * TotalImageScale) + newPosition.X < (ImgZoom.ActualWidth - ((ImgZoom.ActualWidth - rect.Width) / 2)))
                newPosition.X = ImgZoom.ActualWidth - (ImgZoom.ActualWidth * TotalImageScale);

            if ((ImgZoom.ActualHeight * TotalImageScale) + newPosition.Y < ImgZoom.ActualHeight)
                newPosition.Y = ImgZoom.ActualHeight - (ImgZoom.ActualHeight * TotalImageScale);

            ImagePosition = newPosition;

            ApplyPosition();
        }

        /// <summary>
        /// Applies the computed position to the image control.
        /// </summary>
        private void ApplyPosition()
        {
            ((CompositeTransform)ImgZoom.RenderTransform).TranslateX = ImagePosition.X;
            ((CompositeTransform)ImgZoom.RenderTransform).TranslateY = ImagePosition.Y;
        }

        /// <summary>
        /// Resets the zoom to its original scale and position
        /// </summary>
        private void ResetImagePosition()
        {
            TotalImageScale = 1;
            ImagePosition = new Point(0, 0);
            ApplyScale();
            ApplyPosition();
        }

        /// <summary>
        /// Checks that dragging by the given amount won't result in empty space around the image
        /// </summary>
        private bool IsDragValid(double scaleDelta, Point translateDelta)
        {
            if (ImagePosition.X + translateDelta.X > (ImgZoom.ActualWidth - rect.Width) / 2 || ImagePosition.Y + translateDelta.Y > 0)
                return false;

            if ((ImgZoom.ActualWidth * TotalImageScale * scaleDelta) + (ImagePosition.X + translateDelta.X) < ImgZoom.ActualWidth - ((ImgZoom.ActualWidth - rect.Width) / 2))
                return false;

            if ((ImgZoom.ActualHeight * TotalImageScale * scaleDelta) + (ImagePosition.Y + translateDelta.Y) < ImgZoom.ActualHeight)
                return false;

            return true;
        }

        /// <summary>
        /// Tells if the scaling is inside the desired range
        /// </summary>
        private bool IsScaleValid(double scaleDelta)
        {
            return (TotalImageScale * scaleDelta >= 1) && (TotalImageScale * scaleDelta <= MAX_IMAGE_ZOOM);
        }

        #endregion

        private void ClipImage()
        {
            RectangleGeometry geo = new RectangleGeometry();

            System.Windows.Shapes.Rectangle r = (System.Windows.Shapes.Rectangle)(from c in this.ImageView.Children where c.Opacity == OPACITY select c).First();
            GeneralTransform gt = r.TransformToVisual(ImgZoom);
            Point point = gt.Transform(new Point(0, 0));
            double currentWidth = ImgZoom.ActualWidth * TotalImageScale;
            double currentHeight = ImgZoom.ActualHeight * TotalImageScale;

            double actualWidth = bitmapSource.PixelWidth * 1.0f;
            double actualHeight = bitmapSource.PixelHeight * 1.0f;

            double ratio = actualWidth / currentWidth;

            WriteableBitmap writeableBitmap = new WriteableBitmap(bitmapSource);
            if (IsCamera == "t")
            {
                if (bitmapSource.PixelWidth > bitmapSource.PixelHeight)
                    writeableBitmap = writeableBitmap.Rotate(90);
                else
                    writeableBitmap = writeableBitmap.Rotate(-90);
            }
            var imageSource = writeableBitmap.Crop((int)(point.X * ratio*TotalImageScale), (int)(point.Y * ratio*TotalImageScale), (int)(rect.Width * ratio), (int)(rect.Height * ratio));
            if ((FinishChooseImageEvent!=null) &&  (IsCamera != "t"))
            {
                //if (IsCamera == string.Empty)
                //{
                    FinishChooseImageEvent(imageSource);
                    NavigationService.RemoveBackEntry();
                    NavigationService.GoBack();
                //}
                
            }
            if (IsCamera == "t")
            {
                MainPage.ImageStream = imageSource;
                
                NavigationService.Navigate(new Uri("/MainPage.xaml?iscamera=t", UriKind.Relative));
                
            }
        }

        private void OkApplicationBarIconButton_Click(object sender, EventArgs e)
        {
            ClipImage();
            
        }

    }
}